package com.topnav.mc.involve.http;

import com.js.lib.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @类名: HttpUtil
 * @说明: http工具类
 *
 * @author: kenny
 * @Date	2017年10月26日上午11:19:42
 * 修改记录：
 *
 * @see
 */

@Slf4j
public class HttpUtil {
	public static final int METHOD_GET=0;
	public static final int METHOD_POST=1;

	private static final int Connect_Timeout = 60000;
	private static final int Connection_Request_Timeout = 60000;
	private static final int Socket_Timeout = 60000;


	/**
	 * 带普通 参数的Post
	 * @param uri
	 * @param pairs
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 * @throws
	 */
	public static String doPost(String uri, HttpPairs pairs, RequestInter requestInter)
			throws ClientProtocolException, IOException,Exception, HttpException {
		if (pairs == null)
			throw new HttpException("pairs must not be null");
		return  postMethod(uri,pairs,requestInter);
	}

	/**
	 * 带 josn参数的Post
	 * @param uri
	 * @param json
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 */
	public static String doPost(String uri, String json, RequestInter requestInter)
			throws ClientProtocolException, IOException,Exception, HttpException {
		return  postMethod(uri,json,requestInter);
	}

	/**
	 * 带设置超时间的请求
	 * @param uri
	 * @param json
	 * @param requestInter
	 * @param timeoutMill 超时毫秒
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 */
	public static String doPost(String uri, String json, RequestInter requestInter, int timeoutMill)
			throws ClientProtocolException, IOException,Exception, HttpException {
		return  postMethod(uri,json,requestInter,timeoutMill);
	}

	/**
	 * 带map<String, Object>参数的Post
	 * @param uri
	 * @param paramsMap
	 * @return
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String doPost(String uri, Map<String, Object> paramsMap, RequestInter requestInter)
			throws ClientProtocolException, HttpException, IOException{
		if (paramsMap == null)
			throw new HttpException("paramsMap must not be null");

		HttpPairs pairs = new HttpPairs();
        for (String key : paramsMap.keySet()) {
        	pairs.add((String)key, String.valueOf(paramsMap.get(key)));
        }
		return  postMethod(uri,pairs,requestInter);
	}
	/**
	 * 带HttpPairs参数的Delete
	 * @param uri
	 * @param pairs
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 */
	public static String doDelete(String uri, HttpPairs pairs, RequestInter requestInter)
			throws ClientProtocolException, IOException,Exception, HttpException {
		if (pairs == null)
			throw new HttpException("pairs must not be null");
		return  deleteMethod(uri,pairs,requestInter);
	}

	/**
	 * 带json参数的Delete
	 * @param uri
	 * @param json
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 */
	public static String doDelete(String uri, String json,RequestInter requestInter)
			throws ClientProtocolException, IOException,Exception, HttpException {
		return  deleteMethod(uri,json,requestInter);
	}

	/**
	 * 带Map参数的Delete
	 * @param uri
	 * @param paramsMap
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String doDelete(String uri, Map<Object, Object> paramsMap, RequestInter requestInter)
			throws ClientProtocolException, HttpException, IOException{
		if (paramsMap == null)
			throw new HttpException("paramsMap must not be null");

		HttpPairs pairs = new HttpPairs();
        for (Object key : paramsMap.keySet()) {
        	pairs.add((String)key, String.valueOf(paramsMap.get(key)));
        }
		return  deleteMethod(uri,pairs,requestInter);
	}

	/**
	 * 带参数的Get
	 * @param uri
	 * @param pairs
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 */
	public static String doGet(String uri, HttpPairs pairs, RequestInter requestInter)
			throws ClientProtocolException, IOException,Exception, HttpException {

		if (pairs != null && pairs.getPairs().size() > 0)
			uri = uri + "?" + pairs.toString();
		return  getMethod(uri,requestInter);
	}

	/**
	 * 不带参数的get
	 * @param uri
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws Exception
	 */
	public static String doGet(String uri, RequestInter requestInter)
			throws ClientProtocolException, IOException,Exception, HttpException {
		return  getMethod(uri,requestInter);
	}



	private static String getMethod(String uri, RequestInter requestInter)throws ClientProtocolException, IOException, HttpException {
		HttpResponse response=null;
		String result = null;
		HttpClient httpClient = HttpClients.createDefault();

		HttpUriRequest request=null;
		try{
		    request=new HttpGet(uri);
		    //加入access_token
		    if (requestInter != null)
		    	requestInter.apply(request);

		    response= httpClient.execute(request);
		    if (response != null){
		    	result =  EntityUtils.toString(response.getEntity(),"utf-8");
		    	log.debug(result);
		    	//System.out.println(result);
		    }
		    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK){
		    	log.debug("****访问远程接口失败：url({}),状态码({})",uri,response.getStatusLine().getStatusCode());

		    	Map<String,Object> map = new HashMap<String,Object>();

		    	map = JsonUtil.fromJson(result, Map.class);
		    	if (map.containsKey("message"))
		    		throw new IllegalArgumentException(map.get("message").toString());
		    	else
		    		throw new IllegalArgumentException("未知错误");
		    	//throw new HttpException(String.format("****访问远程接口失败：url(%s),状态码(%s)",
	        	//		u);
		    }

		}catch(Exception e){
			log.debug("****访问远程接口失败：url({}),状态码({})",uri,e.toString());
			throw new IllegalArgumentException(e.getMessage());
		}finally{
			;
		}
		return result;
	}



	/**
	 * json参数 的Post方法
	 * @param uri
	 * @param param
	 * @param requestInter
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 * @throws HttpException
	 */
	private static String postMethod(String uri, Object param, RequestInter requestInter)
			throws ClientProtocolException, IOException, HttpException {
		HttpPost httpPost = new HttpPost(uri);
		//设置超时时间
		httpPost.setConfig(createConfig(0));
		return postMethod0(uri,httpPost,param,requestInter);
	}
	private static String postMethod(String uri, Object param, RequestInter requestInter, int timeoutMill)
			throws ClientProtocolException, IOException, HttpException {
		HttpPost httpPost = new HttpPost(uri);
		//设置超时时间
		httpPost.setConfig(createConfig(timeoutMill));
		return postMethod0(uri,httpPost,param,requestInter);
	}

	private static String postMethod0(String uri, HttpPost httpPost, Object param, RequestInter requestInter){
		CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
		String msg = "****访问远程接口错误：接口名(%s)参数(%s),返回码(%s),%s:%s";
        String paramStr = "";
        String strRequest = "";
        int statusCode = 0;
        try{
		    if (requestInter != null)
		    	requestInter.apply(httpPost);

		    if (param != null){
				//json字串
				if (param instanceof String){
					paramStr = (String)param;
					StringEntity entity = new StringEntity((String)param,"utf-8");
					entity.setContentEncoding("UTF-8");
					entity.setContentType("application/json");
					httpPost.setEntity(entity);
					//键值对编码为param1=value1&param2=value2
				}else if (param instanceof HttpPairs){
					HttpPairs pairs  = (HttpPairs)param;
					paramStr = pairs.toString();
					UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(pairs.getPairs(), "utf-8");
					httpPost.setEntity(urlEncodedFormEntity);
					httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
					httpPost.setEntity(urlEncodedFormEntity);
				}
			}else{
				//UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(pairs.getPairs(), "utf-8");
				//httpPost.setEntity(urlEncodedFormEntity);
				//httpPost.setEntity(urlEncodedFormEntity);
				httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
			}


            //执行 post请求
            CloseableHttpResponse response = closeableHttpClient.execute(httpPost);

            if (response != null){
		    	strRequest =  EntityUtils.toString(response.getEntity(),"utf-8");
		    	log.info(strRequest);
		    	//System.out.println(strRequest);
		    }
            statusCode = response.getStatusLine().getStatusCode();
		    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK){
		    	log.error("****访问远程接口失败：url({}),状态码({})",uri,response.getStatusLine().getStatusCode());
		    	Map<String,Object> map = new HashMap<String,Object>();
		    	try{
			    	map = JsonUtil.fromJson(strRequest, Map.class);
			    	if (map.containsKey("message")){
			    		log.error(String.format(map.get("message").toString()));
			    		throw new IllegalArgumentException(map.get("message").toString());
			    	}else{
			    		log.error("未知错误");
			    		throw new IllegalArgumentException("未知错误");
			    	}

		    	}catch (Exception e){
		    		//如果解析出错
		    		log.error(String.format(String.format(msg,uri,paramStr,statusCode,"返回数据解析错误",strRequest)));
		    		throw new HttpException(String.format(msg,uri,paramStr,statusCode,"返回数据解析错误",strRequest));
		    	}
		    }

        } catch (ParseException e) {
        	log.error(String.format(msg,uri,paramStr,statusCode,"解析异常",e.toString()));
        	throw new HttpException(String.format(msg,uri,paramStr,statusCode,"解析异常",e.toString()));
        } catch(Exception e){
        	log.error(String.format(msg,uri,paramStr,statusCode,"异常",e.toString()));
        	throw new HttpException(String.format(msg,uri,paramStr,statusCode,"异常",e.toString()));
        } finally {
            try {
                if (closeableHttpClient != null) {
                    closeableHttpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();

            }
        }
        return strRequest;
	}

	private static String deleteMethod(String uri, Object param, RequestInter requestInter)
			throws ClientProtocolException, IOException, HttpException {

		CloseableHttpClient closeableHttpClient = HttpClients.createDefault();

        HttpDelete httpDelete = new HttpDelete(uri);
        //设置超时时间
        httpDelete.setConfig(createConfig(0));

        String msg = "****访问远程接口错误：接口名(%s)参数(%s),%s:%s";
        String paramStr = "";
        String strRequest = "";
        try{
        	//加入access_token
        	if (requestInter != null)
		    	requestInter.apply(httpDelete);

        	//json字串
         	if (param instanceof String){
        		paramStr = (String)param;
        		StringEntity entity = new StringEntity((String)param,"utf-8");
    	        entity.setContentEncoding("UTF-8");
    	        entity.setContentType("application/json");
    	        httpDelete.setEntity(entity);
    	    //键值对编码为param1=value1&param2=value2
        	}else if (param instanceof HttpPairs){
        		HttpPairs pairs  = (HttpPairs)param;
        		paramStr = pairs.toString();
                UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(pairs.getPairs(), "utf-8");
                httpDelete.setEntity(urlEncodedFormEntity);
                httpDelete.setHeader("Content-Type", "application/x-www-form-urlencoded");
                httpDelete.setEntity(urlEncodedFormEntity);
        	}

            //执行 post请求
            CloseableHttpResponse response = closeableHttpClient.execute(httpDelete);


		    if (response != null){
		    	strRequest =  EntityUtils.toString(response.getEntity(),"utf-8");
		    }
        } catch (ParseException e) {
        	throw new HttpException(String.format(msg,uri,paramStr,"解析异常",e.toString()));
        } catch(Exception e){
        	throw new HttpException(String.format(msg,uri,paramStr,"异常",e.toString()));
        } finally {
            try {
                if (closeableHttpClient != null) {
                    closeableHttpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return strRequest;
	}



	/**
	 * 创建配置参数，超时设置等
	 * @param millSec 毫秒
	 * @return
	 */
	public static RequestConfig createConfig(int millSec){
        //配置连接超时时间
		if (millSec != 0){
			return  RequestConfig.custom()
					.setConnectTimeout(millSec)
					.setConnectionRequestTimeout(millSec)
					.setSocketTimeout(millSec)
					.setRedirectsEnabled(true)
					.build();
		}else{
			return  RequestConfig.custom()
					.setConnectTimeout(Connect_Timeout)
					.setConnectionRequestTimeout(Connection_Request_Timeout)
					.setSocketTimeout(Socket_Timeout)
					.setRedirectsEnabled(true)
					.build();
		}
 	}


}
